//=========================================================================
// Copyright (C) 2024 The C++ Component Model(COMO) Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//=========================================================================

#include <stdio.h>
#include "checksum.h"
#include "voter_message.h"

// 这些数据的定义顺序必须与 VoterMessageType 的一致
const char* VoterMessageTypeNames[] = {
    "VOTER_NULL",
    "VOTER_SYNC_CLOCK",
    "VOTER_CMD_MONITOR",
    "VOTER_CMD_START_NEW",
    "VOTER_CMD_VOTING_DATA",
    "VOTER_CMD_VOTING_BIGDATA",
    "VOTER_CMD_VOTE",
    "VOTER_RESULT_RAW",
    "VOTER_RESULT_FAIL",
    "VOTER_RESULT_NOID"
};

const char* GetVoterMessageTypeName(int value)
{
    if ((value >= (int)VOTER_NULL) && (value <= (int)VOTER_RESULT_NOID)) {
        return VoterMessageTypeNames[value];
    }
    else {
        return "UNKNOWN";
    }
}

/**
 * BoxVoterMessage
 * 
 * NOTICE: Usage of this function:
 * 1. First, allocation for buffer is required. For example:
 *        char buffer[MAX_VoterMessage_SIZE];
 * 2. Then, call BoxVoterMessage with parameter buffer and bufSize:
 *        BoxVoterMessage(buffer, MAX_VoterMessage_SIZE, ...)
 */
VoterMessage *BoxVoterMessage(char *buffer, int32_t bufSize, char type,
                              uint64_t idTransaction, uint64_t lamportClock,
                              int64_t data, char *str, int32_t rawDataSize)
{
    int sizeTmp;
    VoterMessage *box = (VoterMessage *)buffer;

    // 根据 str 是否为 NULL 决定 sizeTmp
    if (NULL == str) {
        rawDataSize = 0;
        sizeTmp = sizeof(VoterMessage);
    }
    else {
        if (rawDataSize <= 0) {
            rawDataSize = strlen(str) + 1;
        }
        sizeTmp = rawDataSize + VoterMessage_HEAD_LEN;
    }

    // 如果打包空间足够容纳得下数据包
    if (bufSize >= sizeTmp) {
        box->len = rawDataSize + VoterMessage_HEAD_LEN;
        box->type = type;
        box->reservedChars[0] = 'T';   // 幻数, magicNumber: "TJ\0"
        box->reservedChars[1] = 'J';
        box->reservedChars[2] = '\0';
        box->data = data;
        box->idTransaction = idTransaction;
        box->lamportClock = lamportClock;

        // 如果除data(int64_t)外还有str信息，则复制到box->buf中
        if (NULL != str) {
            memcpy(box->buf, str, rawDataSize);
            box->crc32 = crc_32((const unsigned char *)box->buf, rawDataSize);
        }
        else {
            box->buf[0] = '\0';
            box->crc32 = 0;
        }

        return box;
    }

    // No enough space
    return NULL;
}

/**
 * Check BoxVoterMessage
 */
VoterMessage *CheckBoxVoterMessage(VoterMessage *box, int bufSize)
{
    if ((bufSize < (int)sizeof(VoterMessage)) || (box->len < 0)) {
        // 包格式错
        return NULL;
    }

    // Check reservedChars 'T' 'J' '\0'
    if (('T' != box->reservedChars[0]) || ('J' != box->reservedChars[1]) ||
                                              ('\0' != box->reservedChars[2])) {
        return NULL;
    }

    if ((0 != box->crc32) &&
            (box->crc32 != crc_32((const unsigned char *)box->buf,
                                           box->len - VoterMessage_HEAD_LEN))) {
        // 包CRC校检没通过
        return NULL;
    }

    return box;
}
